package com.xiaozhen.jt809.server;

import com.xiaozhen.jt809.adapter.MyClientChannelHandlerAdapter;
import com.xiaozhen.jt809.codec.MsgPackHexDecoder;
import com.xiaozhen.jt809.codec.MsgPackHexEncoder;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.ByteOrder;
import java.util.concurrent.TimeUnit;

/**
 * HISTORY
 *
 * @author zhenweisheng
 * @date 2021/9/16 15:09
 * @description:
 */
@Slf4j
@Service
public class TcpClient {

    @Autowired
    private MyClientChannelHandlerAdapter myClientChannelHandlerAdapter;
    @Autowired
    private MsgPackHexEncoder msgPackHexEncoder;
    @Autowired
    private MsgPackHexDecoder msgPackHexDecoder;

    /**
     * 从链路（客户端）引导入口
     *
     * @param ip
     * @param port
     * @throws Exception
     */
    public void runClient(String ip, int port) {
        NioEventLoopGroup group = new NioEventLoopGroup();
        try {
            log.info("建立从链路链接 TCP-IP:{},TCP-PORT:{}", ip, port);
            Bootstrap client = new Bootstrap();
            client.group(group);
            client.channel(NioSocketChannel.class);
            client.option(ChannelOption.SO_BACKLOG, 128);
            client.option(ChannelOption.TCP_NODELAY, true);
            client.option(ChannelOption.SO_KEEPALIVE, true);
            client.remoteAddress(ip, port);
            client.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    //读超时  写超时  读写超时 单位（秒）
                    pipeline.addLast(new IdleStateHandler(180, 60, 180, TimeUnit.SECONDS));
                    //前置编解码器
                    pipeline.addLast(msgPackHexEncoder);
                    //粘包拆包   根据长度域进行拆包
//                    pipeline.addLast(new LengthFieldBasedFrameDecoder(
//                            ByteOrder.BIG_ENDIAN, 65535,
//                            1, 4, -5, 0,
//                            true));
                    //后置编解码器
                    pipeline.addLast(msgPackHexDecoder);
                    //自定义的编解码器
                    pipeline.addLast(myClientChannelHandlerAdapter);
                }
            });
            ChannelFuture channelFuture = client.connect(ip, port).sync();
            if (channelFuture.isSuccess()) {
                log.info("从链路正在登录");
            }
            channelFuture.channel().closeFuture().addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    //通过回调只关闭自己监听的channel
                    future.channel().close();
                }
            });
        } catch (Exception e) {
            log.error("从链路链接失败");
            group.shutdownGracefully();
        }
    }
}
